﻿using System;
using System.Runtime.InteropServices;
using RayDen.Library.Components;
using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;

namespace RayDen.RayEngine.Core.Types
{
    [StructLayout(LayoutKind.Explicit)]
    public struct PacketRayData
    {
        public const float RayEpsilon = 1e-4f;
        [FieldOffset(0)]
        public Point Org;
        [FieldOffset(12)]
        public float maxT;
        [FieldOffset(16)]
        public byte Theta;
        [FieldOffset(17)]
        public byte Phi;

        public Vector Dir
        {
            get
            {
                return new Vector(
                    DirectionDiscretizationHelper.SinTheta(Theta) * DirectionDiscretizationHelper.CosPhi(Phi),
                    DirectionDiscretizationHelper.SinTheta(Theta) * DirectionDiscretizationHelper.SinPhi(Phi),
                    DirectionDiscretizationHelper.CosTheta(Theta)
                    );
            }

            set
            {
                var dirx = MathLab.Clamp(value.z, -1f, 1f);
                int theta = Convert.ToInt32(Math.Acos(dirx) * (256.0d / Math.PI));
                if (theta > 255)
                    theta = 255;

                Theta = (byte)theta;

                int phi = Convert.ToInt32(Math.Atan2(value.y, value.x) * (256.0d / 2.0 * Math.PI));


                if (phi > 255)
                    phi = 255;
                else

                    if (phi < 0)
                        phi = phi + 256;

                Phi = (byte)phi;
            }
        }

        public float minT { get { return 1e-4f; } }

        public PacketRayData(ref RayData rayData)
        {
            maxT = rayData.maxT;
            Phi = 0;
            Theta = 0;
            Org = rayData.Org;
            Dir = rayData.Dir;
        }
    }
}